package server;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;

/**
 * A class which controls the connection with the client.
 * 
 * @author ic08jh7
 * 
 */
public class ServerConnection {

	private SSLServerSocketFactory sslserversocketfactory;
	private SSLServerSocket sslserversocket;
	private SSLSocket sslsocket;
	private InputStream inputstream;
	private BufferedReader bufferedreader;
	private InputStreamReader inputstreamreader;
	private OutputStream outputstream;
	private OutputStreamWriter outputstreamwriter;
	private BufferedWriter bufferedwriter;
	private final CommandHandler cmdHandler;

	private final int port;

	/**
	 * Creates a new ssl connection with a client and a connection to a database
	 * with user data.
	 * 
	 * @param username
	 *            The username to the database.
	 * @param password
	 *            The password to the database.
	 * @param url
	 *            The url to the database.
	 * @param port
	 *            The port on which the ssl connection will be established.
	 */
	public ServerConnection(String username, String password, String url,
			int port) {
		this.port = port;
		cmdHandler = new CommandHandler(username, password, url);
	}

	/**
	 * Puts the server in a waiting state where it waits for and creates a new
	 * connection
	 * 
	 * @return True if a successful connection was established, else false.
	 */
	public boolean waitForConnection() {
		try {
			sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory
					.getDefault();
			sslserversocket = (SSLServerSocket) sslserversocketfactory
					.createServerSocket(port);
			sslsocket = (SSLSocket) sslserversocket.accept();

			inputstream = sslsocket.getInputStream();
			inputstreamreader = new InputStreamReader(inputstream);
			bufferedreader = new BufferedReader(inputstreamreader);

			outputstream = sslsocket.getOutputStream();
			outputstreamwriter = new OutputStreamWriter(outputstream);
			bufferedwriter = new BufferedWriter(outputstreamwriter);

			System.out.println("Connection established");

			return sslsocket.isConnected();

		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * Searches the connection channel for an input and returns it.
	 * 
	 * @return The input from the ssl channel.
	 */
	public String getInput() {
		try {
			if (isConnected()) {
				String in = bufferedreader.readLine();
				System.out.println("From client: " + in);
				return in;
			}

		} catch (IOException e) {
			e.printStackTrace();
		}
		return "";
	}

	/**
	 * Closes the connection. The waitForConnection() method has to be called in
	 * order to reestablish a connection.
	 */
	public void close() {
		try {
			sslsocket.close();
			sslserversocket.close();
			// sslserversocketfactory = null;
			// sslserversocket = null;
			// sslsocket = null;
			// bufferedreader = null;
			// bufferedwriter = null;

		} catch (IOException e) {
			System.out.println("Unable to close connection.");
		}
	}

	/**
	 * @return True if the connection is closed, else false.
	 */
	public boolean isClosed() {
		return sslsocket.isClosed();
	}

	/**
	 * @return True if the socket is connected, else false.
	 */
	public boolean isConnected() {
		return sslsocket.isConnected();
	}

	/**
	 * Sends a String of data to the client. The data has to follow the
	 * "Johansson-Hallberg" protocol.
	 * 
	 * @param protocolData
	 *            A String of data to be sent to the client.
	 * @throws IOException
	 *             Throws IOException if the writer was unable to write.
	 */
	public void sendToClient(String protocolData) throws IOException {
		String output = cmdHandler.newCommand(protocolData);
		System.out.println("From server: " + output);
		bufferedwriter.write(output + '\n');
		bufferedwriter.flush();

	}

}
